package net.chowda.castcluster.provider;

import net.chowda.castcluster.CastVideoItem;
import net.chowda.castcluster.Video;
import net.chowda.castcluster.VideoProvider;
import net.chowda.castcluster.VideoSource;
import net.chowda.castcluster.util.CorruptFeedException;
import net.chowda.castcluster.util.RSSFeedAggregator;
import net.chowda.castcluster.util.CastClusterConfig;
import net.chowda.castcluster.util.LogUtil;
import net.chowda.castcluster.util.MovieUtil;
import net.chowda.castcluster.util.Base64Util;
import org.apache.log4j.Logger;

import java.io.File;
import java.io.FileFilter;
import java.util.*;

/**
 * all files from /home/blah/videos:
 *
 *  dir|all|/home/blah/videos
 *
 * a single video:
 *
 *  dir|file|/home/blah/videos/myvideo.mov
 *
 */
public class DirectoryProvider extends VideoProvider {
    private static final Logger LOG = LogUtil.getLogger(DirectoryProvider.class);

    /**
     * TODO.... this is pretty hacky.. how do we find out interesting things about files without resorting to freaking extensions...
     */
    private static final HashMap<String,String> MIME_MAP = new HashMap<String,String>();
    static {
        MIME_MAP.put("mov",  "video/quicktime");
        MIME_MAP.put("m4v",  "video/quicktime");
        MIME_MAP.put("avi",  "video/avi");
        MIME_MAP.put("mpg",  "video/mpeg");
        MIME_MAP.put("mpeg", "video/mpeg");
        MIME_MAP.put("mp4",  "video/mp4");
        MIME_MAP.put("mp3",  "audio/mpeg");
        MIME_MAP.put("wmv",  "video/x-ms-wmv");
        MIME_MAP.put("mkv",  "video/x-matroska");
    }

    public String getProviderFeed(String url) {
        try {
            return RSSFeedAggregator.createPodcastFromVideos("files", "somefiles", getProviderVideos(url));
        } catch (CorruptFeedException e) {
            throw new RuntimeException(e);
        }
    }

    public List<Video> getProviderVideos(String url) {
        LOG.info("fetching videos: " + url);
        String type = url.split("\\|")[1];
        String dirPart = url.split("\\|")[2];

        List<Video> videos = new ArrayList<Video>();
        if("all".equals(type)) {
            File dir = new File(dirPart);
            if(dir.exists() && dir.isDirectory()) {
                File[] files = dir.listFiles(new FileFilter() {
                    public boolean accept(File path) {
                        String ext = path.getName().substring(path.getName().lastIndexOf('.')+1);
                        // if the file extension is in our mime-map, it's good to go.
                        return MIME_MAP.get(ext) != null;
                    }
                });
                for (File file : files) {
                    videos.add(fileToVideo(file));
                }
            }
        } else if("rec".equals(type)) {
            // going recursive...
            File dir = new File(dirPart);
            if(dir.exists() && dir.isDirectory()) {
                File[] files = dir.listFiles();
                for (File file : files) {
                    if(file.isDirectory()) {
                        // recurse into dir
                        videos.addAll(getProviderVideos("dir|rec|" + file.getAbsolutePath()));
                    } else {
                        String ext = file.getName().substring(file.getName().lastIndexOf('.')+1);
                        if(MIME_MAP.get(ext) != null) {
                            videos.add(fileToVideo(file));
                        }
                    }
                }
            }

        } else if("file".equals(type)) {
            File file = new File(dirPart);
            if(file.exists() && file.isFile()) {
                videos.add(fileToVideo(file));
            }
        }

        LOG.info("done fetching videos: " + url);
        return videos;
    }

    public String fetchProviderVideo(String url) {
        String filePath = url.split("\\|")[2];

        // ok... not mp4/or mp3... so we'll try and convert it to something iTunes can understand.
        if(!filePath.endsWith(".mp4") && !filePath.endsWith(".mp3")) {
            String destPath = getVideoPath(filePath);
            LOG.info("I don't think iTunes will like this file, converting " + filePath + " to " + destPath);
            if (!new File(destPath).exists()) {
                try {
                    MovieUtil.convertVideoToMPEG4(filePath, destPath);
                    LOG.info("conversion complete: " + filePath + " to " + destPath);
                } catch (Exception e) {
                    LOG.error("problem converting " + filePath + " to " + destPath, e);
                    LOG.error("falling back to none converted...");
                    return filePath;
                }
            } else {
                LOG.info("no need to convert video, we've already done it.");
            }

            filePath = destPath;
        }
        return filePath;
    }

    public void providerCleanupAfterFetch(String url) {
        String filePath = url.split("\\|")[2];
        // ok... not mp4/mp3... that means we did a conversion on it and we should delete the cruft left over.
        if(!filePath.endsWith(".mp4") && !filePath.endsWith(".mp3")) {
            LOG.info("cleaning up temporary converted file for: " + url);
            String destPath = getVideoPath(filePath);
            File file = new File(destPath);
            if (file.exists()) {
                file.delete();
            }
        }
    }

    public List<VideoSource> getProviderSourcesForWebUrl(String url) {
        return new ArrayList<VideoSource>();
    }

    public VideoSource getProviderSourceForCCUrl(String url) {
        VideoSource source = new VideoSource();
        source.setCcUrl(url);
        source.setUrl("file://" + url.split("\\|")[2]);
        source.setName("Local: " + source.getUrl());
        source.setVideos(getProviderVideos(url));
        return source;
    }

    // videoId == absolute path name in this provider.
    // this is only called for videos requiring conversion.
    public String getVideoPath(String videoId) {
        //get just the name part of the filePath
        videoId = videoId.substring(videoId.lastIndexOf(File.separator)+1, videoId.lastIndexOf('.'));
        return CastClusterConfig.getInstance().getGlobalProp(CastClusterConfig.CONFIG_BASE_DIR) + File.separator + "video" + File.separator + videoId + ".mp4";
    }

    private CastVideoItem fileToVideo(File file) {
        String fileName = file.getName();

        CastVideoItem item = new CastVideoItem();
        item.setId(file.getAbsolutePath());
        item.setAuthor(file.getParent());
        item.setDescription(fileName);
        item.setTimeUploaded(new Date(file.lastModified()));
        item.setTitle(replaceNonAlphanumeric(fileName, "_"));
        item.setVidSize(file.length());
        item.setAvailable(true);


        String ext = "mp4";
/*
        String ext = fileName.substring(fileName.lastIndexOf('.')+1);
*/
        if(fileName.endsWith("mp3")) {
            ext = "mp3";
        }
        item.setVidType(MIME_MAP.get(ext));
        if(item.getVidType() == null) {
            throw new IllegalArgumentException("forget to update the file filter or something? bad file: " + file.getAbsolutePath());
        }
        String url = CastClusterConfig.getInstance().getGlobalProp(CastClusterConfig.BASE_URL) + "/PlayList."+ext+"?videoUrl=";

        item.setUrl(url + Base64Util.encode("dir|file|" + file.getAbsolutePath()));
        return item;
    }

    public static String replaceNonAlphanumeric(String str, String subst) {
        StringBuffer ret = new StringBuffer(str.length());
        char[] testChars = str.toCharArray();
        for (char testChar : testChars) {
            if (!Character.isLetterOrDigit(testChar)) {
                ret.append(subst);
            } else {
                ret.append(testChar);
            }
        }
        return ret.toString();
    }
}
